package br.com.sgi.model;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Transient;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;

import org.hibernate.annotations.Type;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.GrantedAuthorityImpl;
import org.springframework.security.core.userdetails.UserDetails;

import br.com.sgi.enuns.PerfilEnum;
import br.com.sgi.util.Criptografia;
import br.com.sgi.util.ICombobox;

@Entity
@Table(name = "USERS")
@NamedQueries({

		@NamedQuery(name = "findByUsername", query = "SELECT usu FROM Users usu " +
				" WHERE usu.username = :username"),
				
		@NamedQuery(name = "buscarUserPorUsername", query = "SELECT usu FROM Users usu " +
				" WHERE usu.sistema.coSeqSistema =:coSistema " +
				" and usu.username = :username"),
	
		@NamedQuery(name = "findAll", query = "SELECT usu FROM Users usu"),
		
		@NamedQuery(name = "buscarUsersPorCoSistema", 
		query = "SELECT usu FROM Users usu " +
				" WHERE usu.sistema.coSeqSistema = :coSistema" +
				" and usu.username != 'adms' "),
				
		@NamedQuery(name = "removerUsersPorUsername", 
		query = "DELETE FROM Users usu " +
				" WHERE usu.sistema.coSeqSistema =:coSistema " +
				" AND usu.username = :username")			

})
public class Users implements Serializable, UserDetails, ICombobox {

	private static final long serialVersionUID = -8451679170281063697L;

	@Id
	@NotNull
	@Size(min = 1, max = 50)
	@Column(name="USERNAME",unique = true)
	private String username;

	@NotNull
	@Size(min = 1, max = 50)
	private String password;

	@OneToMany(mappedBy="username",  fetch = FetchType.EAGER, cascade={CascadeType.ALL})
	private List<Authorities> authorities;

	@NotNull
	private boolean enabled;
	
	@ManyToOne(fetch=FetchType.EAGER)
	@JoinColumn(name="CO_SISTEMA")
	private Sistema sistema;
	
	@ManyToOne(fetch=FetchType.EAGER)
	@JoinColumn(name="CO_IGREJA")
	private Igreja igreja; 
	
	@OneToMany(mappedBy="users", cascade={CascadeType.ALL})
	private List<UsersIgreja> igrejasAutorizadas;
	
	
	@Size(min = 1, max = 100)
	private String nome;
	
	
	@Size(min = 1, max = 100)
	private String email;
	

	@Transient
	public Collection<GrantedAuthority> getAuthorities() {
		List<GrantedAuthority> result =	new ArrayList<GrantedAuthority>();
		for (Authorities aut : authorities) {
			result.add(new GrantedAuthorityImpl(aut.getAuthority()));
		}
		return result;
	}
	
	@Transient
	public Set<String> getAuthority() {
		Set<String> roles = null;
		roles = new HashSet<String>();
		for (Authorities aut : authorities) {
			roles.add(aut.getAuthority().toString());
		}
		return roles;
	}
	
	@Transient
	private String perfil;
	
	@Column(name="PRIMEIRO_ACESSO", length=1)	
	@Type(type = "br.com.sgi.type.SimNaoType")
	private Boolean primeiroAcesso;
	
	public boolean isEnabled() {
		return enabled;
	}

	public void setEnabled(boolean enabled) {
		this.enabled = enabled;
	}

	public void setUsername(String username) {
		if(username != null)
			username = username.toLowerCase();
		this.username = username;
	}

	public void setPassword(String password) {
		if(password != null && password.isEmpty())
			password = Criptografia.md5(password);
		this.password = password;
	}

	public void setAuthorities(List<Authorities> authorities) {
		this.authorities = authorities;
	}

	@Transient
	public boolean isAccountNonExpired() {
		return true;
	}

	@Transient
	public boolean isAccountNonLocked() {
		return true;
	}

	@Transient
	public boolean isCredentialsNonExpired() {
		return true;
	}

	public String getUsername() {

		return username;
	}

	public String getPassword() {
		return password;
	}

	public Sistema getSistema() {
		return sistema;
	}

	public void setSistema(Sistema sistema) {
		this.sistema = sistema;
	}

	public List<UsersIgreja> getIgrejasAutorizadas() {
		return igrejasAutorizadas;
	}

	public void setIgrejasAutorizadas(List<UsersIgreja> igrejasAutorizadas) {
		this.igrejasAutorizadas = igrejasAutorizadas;
	}

	public Igreja getIgreja() {
		return igreja;
	}

	public void setIgreja(Igreja igreja) {
		this.igreja = igreja;
	}

	public String getNome() {
		return nome;
	}

	public void setNome(String nome) {
		this.nome = nome;
	}

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		if(email != null)
			email = email.toLowerCase();
		this.email = email;
	}

	public String getPerfil() {
		if(getAuthority().contains(PerfilEnum.ROLE_ADMIN_GERAL.getCodigo()))
			perfil = PerfilEnum.ROLE_ADMIN_GERAL.getDescricao();
		else
			if(getAuthority().contains(PerfilEnum.ROLE_ADMIN_LOCAL.getCodigo()))
				perfil = PerfilEnum.ROLE_ADMIN_LOCAL.getDescricao();
			else
				if(getAuthority().contains(PerfilEnum.ROLE_ADMIN_REGIONAL.getCodigo()))
					perfil = PerfilEnum.ROLE_ADMIN_REGIONAL.getDescricao();
				else
					if(getAuthority().contains(PerfilEnum.ROLE_USUARIO_LOCAL.getCodigo()))
						perfil = PerfilEnum.ROLE_USUARIO_LOCAL.getDescricao();
		
		return perfil;
	}

	public void setPerfil(String perfil) {
		this.perfil = perfil;
	}

	public Boolean getPrimeiroAcesso() {
		return primeiroAcesso;
	}

	public void setPrimeiroAcesso(Boolean primeiroAcesso) {
		this.primeiroAcesso = primeiroAcesso;
	}

	@Override
	public Object getValue() {
		return getUsername();
	}
	
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result	+ ((username == null) ? 0 : username.hashCode());
		return result;
	}
	
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Users other = (Users) obj;
		if (username == null) {
			if (other.username!= null)
				return false;
		} else if (!username.equals(other.username))
			return false;
		return true;
	}
	
}
